import os 
def check_lowering_logs(logs, lift_log, skip_log, fallback_log, fall_back_log):
    keywords = [
        "Lift AscBackend node",
        "Skip lowering node",
        "Fallback lowering for node",
        "Fall back lowering for node"
    ]
    for index, line in enumerate(logs):
        # print(line)
        if keywords[0] in line:
            index0 = line.find(keywords[0])
            if index0 != -1:
                lift_log.append(line[index0:] + "; log line: " + str(index + 1))
        if keywords[1] in line:
            index1 = line.find(keywords[1])
            if index1 != -1:
                skip_log.append(line[index1:] + "; log line: " + str(index + 1))
        if keywords[2] in line:
            index2 = line.find(keywords[2])
            if index2 != -1:
                fallback_log.append([line[index2:] + "; log line: " + str(index + 1), index]) # 当前日志,前一行日志 获取ascirdtype不支持时需要用到
        if keywords[3] in line:
            index3 = line.find(keywords[3])
            if index3 != -1:
                fall_back_log.append(line[index3:] + "; log line: " + str(index + 1))

def print_logs(logs):
    for line in logs:
        print(line)

def str_in_outputs(node_name, outputs):
    for output in outputs:
        if node_name == output[0]:
            return True
    return False

# Lift AscBackend node %s, node list is [opType(opName1), opType2(opName2)]
def check_lift_log(lift_log, nofuse_nodes, outputs):
    lifting_nodes = []
    lifting_original_nodes = []
    for line in lift_log:
        # print(line)
        parts = line.split(", node list")
        autofuse_node = parts[0].split(" ")[-1]
        node_list_str = parts[1].split("[")[1].split("]")[0]
        node_list = []
        for node in node_list_str.split(", "):
            # print(node)
            node_name = node.strip("()").split("(")[1]
            node_list.append(node_name)
        # print(node_list)
        if "Lift AscBackend nodes" in line:
            for node in nofuse_nodes:
                if node in node_list:
                    isfind = str_in_outputs(node, outputs)
                    if not isfind:
                        outputs.append([node, "", "lowering", "lowering失败,待分析", line, ""])
            if not nofuse_nodes:
                for node in node_list:
                    isfind = str_in_outputs(node, outputs)
                    if not isfind:
                        outputs.append([node, "", "lowering", "lowering失败,待分析", line, ""])
            continue
        for node in nofuse_nodes:
            if node in node_list:
                isfind = False
                for origin_node in lifting_original_nodes:
                    if origin_node == node:
                        isfind = True
                        break
                if not isfind:
                    lifting_nodes.append(autofuse_node)
                    lifting_original_nodes.append(node)
        if not nofuse_nodes:
            node_str = ""
            for node in node_list:
                node_str += node + " "
            isfind = False
            for origin_node in lifting_original_nodes:
                if origin_node == node:
                    isfind = True
                    break
            if not isfind:
                lifting_nodes.append(autofuse_node)
                lifting_original_nodes.append(node_str)
    return [lifting_nodes, lifting_original_nodes]

# skip lowering node 高频错误注册
skip_no_sym = ["No symbolic desc attr", "no sym shape"]
skip_as_map = {
    "Gather is in high_performance mode" : "Gather原算子为高性能模式",
    " " : "lowering失败"
}
skip_because_map = {
    "No lowering registered" : "算子类型未注册lowerng",
    "check IR compatibility" : "算子原型不规范",
    " " : "节点不需要lowering"
}
def check_skip_lowering_log(skip_log, nofuse_nodes, outputs):
    no_symbolize_nodes = []
    for line in skip_log:
        # print(line)
        is_no_sym = False
        for no_sym in skip_no_sym:
            if no_sym in line:
                is_no_sym = True
                parts = line.split(",")
                node_name = parts[0].split(" ")[-1]
                # print(node_name)
                isfind = str_in_outputs(node_name, outputs)
                if not isfind and (node_name in nofuse_nodes or not nofuse_nodes):
                    no_symbolize_nodes.append(node_name)
                break
        if is_no_sym:
            continue
        parts = line.split("because")
        if len(parts) > 1:
            node_name = parts[0].split(" ")[3].split(",")[0]
            # print(node_name)
            isfind = str_in_outputs(node_name, outputs)
            if isfind:
                continue
            if node_name in nofuse_nodes or not nofuse_nodes:
                for key, value in skip_because_map.items():
                    if key in line:
                        outputs.append([node_name, "", "lowering", value, line, ""])
                        break
        parts = line.split("as: ")
        if len(parts) > 1:
            node_name = parts[0].split(" ")[3].split(",")[0]
            if node_name in nofuse_nodes or not nofuse_nodes:
                isfind = str_in_outputs(node_name, outputs)
                if not isfind:
                    for key, value in skip_as_map.items():
                        if key in line:
                            outputs.append([node_name, "", "lowering", value, line, ""])
                            break

    return no_symbolize_nodes

fallback_map = {
    "dtype unsupported kernel box" : "ascirdtype不支持",
    "oversize" : "Kernelbox超大",
    " " : "lowering失败"
}
def check_fallback_lowering_log(inputs, fallback_log, nofuse_nodes, outputs, no_symbolize_nodes):
    for line, index in fallback_log:
        # print(line)
        parts = line.split("as:")
        if len(parts) > 1:
            node_name = parts[0].split(" ")[4].split(",")[0]
            isfind = str_in_outputs(node_name, outputs)
            if node_name in no_symbolize_nodes:
                isfind = True
            if isfind:
                continue
            if node_name in nofuse_nodes or not nofuse_nodes:
                for key, value in fallback_map.items():
                    if key in line:
                        if key == "dtype unsupported kernel box" and index - 2 >= 0:
                            line = inputs[index - 2] + inputs[index - 1] + line
                        outputs.append([node_name, "", "lowering", value, line, ""])
                        break

fall_back_map = {
    "unsupported scalar AscendC IR graph" : "不支持纯scalar图",
    " " : "生成Ascbackend失败"
}
def check_fall_back_lowering_log(fall_back_log, nofuse_nodes, outputs):
    for line in fall_back_log:
        # print(line)
        parts = line.split("As ")
        if len(parts) > 1:
            node_list = []
            for node in parts[0].split("[")[1].split("]")[0].split(", "):
                node_name = node.split("(")[0]
                node_list.append(node_name)
            if not nofuse_nodes:
                for tmp_node in node_list:
                    isfind = str_in_outputs(tmp_node, outputs)
                    if not isfind:
                        for key, value in fall_back_map.items():
                            if key in line:
                                outputs.append([tmp_node, "", "lowering", value, line, ""])
                                break
            else:
                for node in nofuse_nodes or not nofuse_nodes:
                    if node in node_list:
                        isfind = str_in_outputs(node, outputs)
                        if not isfind:
                            for key, value in fall_back_map.items():
                                if key in line:
                                    outputs.append([node, "", "lowering", value, line, ""])
                                    break

def check_without_nofuse(no_symbolize_nodes, lifting_original_nodes, nofuse_nodes, outputs):
    tmp_outputs = outputs
    for node in nofuse_nodes:
        isfind = str_in_outputs(node, tmp_outputs)
        if isfind:
            continue
        for no_symbolize_node in no_symbolize_nodes:
            if node == no_symbolize_node:
                isfind = True
                break
        if isfind:
            continue
        for lifting_original_node in lifting_original_nodes:
            if node == lifting_original_node:
                isfind = True
                break
        if not isfind:
            outputs.append([node, "", "lowering", "日志未找到", "", ""])

def cannot_lowering(inputs, nofuse_nodes, outputs):
    lift_log = []
    skip_log = []
    fallback_log = []
    fall_back_log = []
    # 获取四种不同开头的lowering日志
    check_lowering_logs(inputs, lift_log, skip_log, fallback_log, fall_back_log)
    # 分别处理融合回滚节点、lowering前/lowering、kernelbox处理阶段、ascbackend处理阶段
    [lifting_nodes, lifting_original_nodes] = check_lift_log(lift_log, nofuse_nodes, outputs)
    no_symbolize_nodes = check_skip_lowering_log(skip_log, nofuse_nodes, outputs)
    check_fallback_lowering_log(inputs, fallback_log, nofuse_nodes, outputs, no_symbolize_nodes)
    check_fall_back_lowering_log(fall_back_log, nofuse_nodes, outputs)

    check_without_nofuse(no_symbolize_nodes, lifting_original_nodes, nofuse_nodes, outputs)
    # print("before lowering log")
    # for output in outputs:
    #     print(output)
    # print("after lowering log")
    # print("lifting node")
    # print(lifting_nodes)
    # print("lifting_original_nodes")
    # print(lifting_original_nodes)
    # print("no_sym")
    # print(no_symbolize_nodes)
    # print("nofuse_nodes " + str(len(nofuse_nodes)) + " no_symbolize_nodes " + str(len(no_symbolize_nodes)) + " lifting " + str(len(lifting_nodes)) + " lifting_origin " + str(len(lifting_original_nodes)) + " output " + str(len(outputs)))
    return [no_symbolize_nodes, lifting_nodes, lifting_original_nodes]
